﻿using ColorWanted.Plugin.Base;
using ColorWanted.plugins.error;
using ColorWanted.plugins.events;
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Forms;

namespace ColorWanted.plugins
{
    public partial class PluginForm : Form
    {
        private readonly PluginManager<PluginBase> manager;
        private static PluginForm instance;

        public PluginForm()
        {
            InitializeComponent();

            manager = new PluginManager<PluginBase>(filePrefix: "ColorWanted.Plugin.");
            // 处理插件管理器发出的事件
            manager.OnAssemblyLoading += PluginManager_OnAssemblyLoading;
            manager.OnAssemblyLoaded += PluginManager_OnAssemblyLoaded;
            manager.OnError += PluginManager_OnError;
            manager.OnInstanceCreating += PluginManager_OnInstanceCreating;
            manager.OnInstanceCreated += PluginManager_OnInstanceCreated;

            LoadPlugins();
        }

        private void LoadPlugins()
        {
            string baseFile = typeof(PluginBase).Module.FullyQualifiedName;
            manager.Load(pluginName => pluginName != baseFile);
        }

        internal static PluginForm Create()
        {
            // 检查目标 DLL 文件是否存在
            var target = "ColorWanted.Plugin.Base.dll";
            var exePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var baseFile = Path.Combine(exePath, target);
            if (!File.Exists(baseFile))
            {
                MessageBox.Show($"未在此目录下找到插件支持文件 {target}，无法使用插件功能");
                return null;
            }

            if (instance != null && (instance.Disposing || instance.IsDisposed))
            {
                instance = null;
            }
            if (instance == null)
            {
                instance = new PluginForm();
            }
            return instance;
        }

        private static void PluginManager_OnAssemblyLoading(object sender, PluginAssemblyLoadingArgs e)
        {
            Console.WriteLine($"准备从文件\"{e.FileName}\"加载程序集");
        }

        private static void PluginManager_OnAssemblyLoaded(object sender, PluginAssemblyLoadedArgs e)
        {
            Console.WriteLine($"从文件\"{e.FileName}\"加载程序集\"{e.Assembly}\"成功");
        }

        private static void PluginManager_OnInstanceCreating(object sender, PluginInstanceCreatingArgs e)
        {
            Console.WriteLine($"准备从程序集\"{e.Assembly}\"加载类型\"{e.Class}\"");
        }

        private void PluginManager_OnInstanceCreated(object sender, PluginInstanceCreatedArgs<PluginBase> e)
        {
            var plugin = e.Instance;
            Console.WriteLine($"从程序集\"{e.Assembly}\"加载类型\"{e.Class}\"成功");
            Console.WriteLine($"插件名称: {plugin.Name}, 版本: {plugin.Version}");
            plugin.Load();

            var item = new ListViewItem(new string[]
            {
                plugin.Name,
                plugin.Version.ToString(),
                plugin.Author,
                plugin.Description,
                plugin.Url
            })
            {
                Tag = plugin
            };
            listPlugins.Items.Add(item);
        }

        private static void PluginManager_OnError(object sender, PluginErrorEventArgs e)
        {
            switch (e.ErrorType)
            {
                case PluginErrorTypes.None:
                    break;
                case PluginErrorTypes.InvalidDll:
                    Console.WriteLine($"文件\"{e.FileName}\"不是有效的 dll: {e.Exception}");
                    break;
                case PluginErrorTypes.CannotLoadClassTypes:
                    Console.WriteLine($"无法从文件\"{e.FileName}\"中加载类型: {e.Exception}");
                    break;
                case PluginErrorTypes.ImplementionClassNotFound:
                    Console.WriteLine($"在文件\"{e.FileName}\"中没有找到实现了指定接口的类");
                    break;
                case PluginErrorTypes.IllegalClassDefinition:
                    Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类，但是其声明不是 class 或声明为 abstract 或不是 public");
                    break;
                case PluginErrorTypes.DefaultConstructorNotFound:
                    Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类，但未找到默认的无参构造函数");
                    break;
                case PluginErrorTypes.InstanceCreateFailed:
                    Console.WriteLine($"在文件\"{e.FileName}\"中找到了实现指定接口的类 \"{e.ClassType}\"，但是创建实例时抛出了异常: {e.Exception}");
                    break;
                case PluginErrorTypes.Unkown:
                    Console.WriteLine("未知错误");
                    break;
                default:
                    break;
            }
        }

        private void listPlugins_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            var item = listPlugins.GetItemAt(e.X, e.Y);
            if (item == null)
            {
                return;
            }
            var plugin = (PluginBase)item.Tag;
            plugin.Open();
        }

        private void PluginForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            Dispose();
            GC.Collect();
        }

        private void btnOpenMarket_Click(object sender, EventArgs e)
        {
            Process.Start("https://gitee.com/hyjiacan/ColorWanted.Market");
        }
    }
}
